﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JVMTI_CONN_CONNECT
{
    /// <summary>
    /// TODO: see if needs to be extracted with ResourceLifeCycleViewModel.
    /// </summary>
    public class LifeCycleViewModel
    {
        public string DisplayName
        {
            get
            {
                if (friendlyName == null || friendlyName.Trim() == "")
                    return Id;
                return friendlyName;
            }
            set
            {
                friendlyName = value;
            }
        }
        public string Id { get; set; }
        string friendlyName;
        /// <summary>
        /// ordered by timestamp
        /// </summary>
        public IList<ILifeEvent> KeyEvents { get; set; }
        //public int StartedThread { get; set; }
        public double StartTimeStamp { get { return KeyEvents.Count != 0 ? KeyEvents[0].Timestamp : double.MaxValue; } }
        public double EndTimeStamp { get { return KeyEvents.Count != 0 ? KeyEvents.Last().Timestamp : double.MinValue; } }
        public IEnumerable<KeyValuePair<string, double>> ResourceContentionBreakDown
        {
            get
            {
                var contentionList = new List<KeyValuePair<string, double>>();
                var eventsGroupedByResources = KeyEvents.AsParallel<ILifeEvent>().Where<ILifeEvent>(jevent => (jevent.MethodName & (JvmtiMethodEnum.MonitorContendedEnter | JvmtiMethodEnum.MonitorContendedEntered | JvmtiMethodEnum.ObjectWait | JvmtiMethodEnum.ObjectWaited)) != 0).OrderBy<ILifeEvent, double>(jevent => jevent.Timestamp);
                var groupped = eventsGroupedByResources.GroupBy<ILifeEvent, string>(jevent => jevent.Object); //the orderby may be redundant, as KeyEvents are already ordered. Beauty of dynamics, again.
                //for contentions, must be well-interleaved.
                foreach (var resourceEvents in groupped)
                {
                    var asList = resourceEvents.ToList();
                    double blockingTimeForCurrentResource = 0;
                    for (int i = 0; i < asList.Count; i++)
                    {
                        if (asList[i].EmpahsizingEvent())
                        {
                            for (int j = i; j < asList.Count; j++)
                            {
                                if (!asList[j].EmpahsizingEvent())
                                {
                                    //j should be i+1, normally.
                                    blockingTimeForCurrentResource += asList[j].Timestamp - asList[i].Timestamp;
                                    i = j;
                                    break;
                                }
                            }
                        }
                    }
                    contentionList.Add(new KeyValuePair<string, double>(resourceEvents.Key, blockingTimeForCurrentResource));
                }
                return contentionList;

            }
        }
        public LifeCycleViewModel(string threadId, IEnumerable<ILifeEvent> keyEvents)
        {
            //StartedThread = -1;
            this.Id = threadId;
            KeyEvents = keyEvents.OrderBy<ILifeEvent, double>(ievent => ievent.Timestamp).ToList();
        }
        public override bool Equals(object obj)
        {
            if (obj == null) return false;
            var test = obj as LifeCycleViewModel;
            if (test != null && Id == test.Id) return true;
            return false;
        }
    }

    public class LifeCycleViewModels : List<LifeCycleViewModel>//, INotifyPropertyChanged
    {
        //this is ugly.
        //public ILifeEvent SelectedValue
        //{
        //    get
        //    {
        //        return selectedValue;
        //    }
        //    internal set
        //    {
        //        if (selectedValue != value)
        //        {
        //            selectedValue = value; firePropertyChangedCallback("SelectedValue");
        //        }
        //    }
        //}
        //private void firePropertyChangedCallback(string name)
        //{
        //    if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(name));
        //}
        //public event PropertyChangedEventHandler PropertyChanged;
    }


}
